﻿using System.Collections.Generic;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

using SmlEngine;
using SmlEngine.Sprites.Components;

namespace SmlEngine.Sprites
{
    public class  Sprite : SpriteBase
    {
        #region Properties
        /// <summary>
        /// A list of the SpriteComponents of this Sprite.
        /// </summary>
        public List<SpriteComponent> Components { get; private set; }

        #region Position

        /// <summary>
        /// The previous position.
        /// </summary>
        public Vector2 PreviousPosition { get; set; }
        /// <summary>
        /// The current position.
        /// </summary>
        public Vector2 Position { get; set; }
        /// <summary>
        /// The project position, determined during updates.
        /// </summary>
        public Vector2 ProjectedPosition { get; set; }

        /// <summary>
        /// The velocity in pixels per frame(?)
        /// </summary>
        public Vector2 Velocity { get; set; }
        /// <summary>
        /// The acceleration of the sprite.
        /// </summary>
        public Vector2 Acceleration { get; set; }

        /// <summary>
        /// The projected bounds of this sprite after updating.
        /// </summary>
        public BoundingRectangle ProjectedBounds
        {
            get { return new BoundingRectangle(ProjectedPosition.X, ProjectedPosition.Y, Size.X, Size.Y); }
        }

        #endregion

        #endregion

        /// <summary>
        /// Constructs a new Sprite instance.
        /// </summary>
        public Sprite()
        {
            Components = new List<SpriteComponent>();
        }

        /// <summary>
        /// Updates this Sprite.
        /// </summary>
        /// <param name="gameTime">Timing information for the game.</param>
        public virtual void Update(GameTime gameTime)
        {
            UpdatePosition(gameTime);
            UpdateComponents(gameTime);
        }

        /// <summary>
        /// Updates the position.
        /// </summary>
        /// <param name="gameTime">Timing information for the game.</param>
        protected void UpdatePosition(GameTime gameTime)
        {
            float delta = gameTime.GetElapsedSeconds();

            PreviousPosition = Position; // Shift positions
            Position = ProjectedPosition;

            Velocity += Acceleration * delta; // Update velocity

            ProjectedPosition += Velocity * delta; // Project position using current velocity
        }

        /// <summary>
        /// Updates the components of this sprite.
        /// </summary>
        /// <param name="gameTime">Timing information for the game.</param>
        protected void UpdateComponents(GameTime gameTime)
        {
            foreach (SpriteComponent component in Components)
            {
                component.Update(gameTime);
            }
        }

        /// <summary>
        /// Draws this sprite.
        /// </summary>
        /// <param name="gameTime">Timing information for the game.</param>
        /// <param name="spriteBatch">The SpriteBatch to draw onto.</param>
        public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            foreach (SpriteComponent component in Components)
            {
                component.Draw(gameTime, spriteBatch);
            }
        }
    }
}
